FrameLib  0.7
DSP processing with frames of arbitrary timing and length
FrameLib_Object.h
Go to the documentation of this file.
1 
2 #ifndef FRAMELIB_BLOCK_H
3 #define FRAMELIB_BLOCK_H
4 
5 #include "FrameLib_Types.h"
6 #include "FrameLib_Context.h"
7 #include "FrameLib_Parameters.h"
8 #include <string>
9 #include <sstream>
10 #include <iostream>
11 
12 template <class T>
14 {
15 
16 public:
17 
18  FrameLib_Queueable() : mNext(NULL) {}
19 
20  class Queue
21  {
22  typedef void (T::*Method)(Queue *);
23 
24  public:
25 
26  Queue() : mMethod(NULL), mTop(NULL), mTail(NULL) {}
27  Queue(T *object, Method method) : mMethod(NULL), mTop(NULL), mTail(NULL) { add(object, method); }
28 
29  void add(T *object, Method method)
30  {
31  // Do not re-add if already in queue
32 
33  if (object->FrameLib_Queueable<T>::mNext != NULL)
34  return;
35 
36  if (!mTop)
37  {
38  // Queue is empty - add and start processing the queue
39 
40  mMethod = method;
41  mFirst = mTop = mTail = object;
42 
43  while (mTop)
44  {
45  object = mTop;
46  (object->*method)(this);
47  mTop = object->FrameLib_Queueable<T>::mNext;
48  object->FrameLib_Queueable<T>::mNext = NULL;
49  }
50 
51  mMethod = NULL;
52  mFirst = mTail = NULL;
53  }
54  else
55  {
56  assert (method == mMethod && "Cannot add items to open queue for another method");
57 
58  // Add to the queue (which is already processing)
59 
60  mTail->FrameLib_Queueable<T>::mNext = object;
61  mTail = object;
62  }
63  }
64 
65  T *getFirst() const { return mFirst; }
66 
67  private:
68 
69  // Deleted
70 
71  Queue(const Queue&);
72  Queue& operator=(const Queue&);
73 
74  Method mMethod;
75 
76  T *mFirst;
77  T *mTop;
78  T *mTail;
79  };
80 
81 private:
82 
83  T *mNext;
84 };
85 
86 // FrameLib_Object
87 
88 // This abstract template class outlines the basic functionality that objects (blocks / DSP / multichannel must provide)
89 
90 template <class T>
92 {
93 
94 protected:
95 
96  template <class U>
98  {
99  UntypedConnection() : mObject(NULL), mIndex(0) {}
100  UntypedConnection(U *object, unsigned long index) : mObject(object), mIndex(index) {}
101 
103  unsigned long mIndex;
104  };
105 
106 private:
107 
109  typedef typename std::vector< T *>::iterator ObjectIterator;
110  typedef typename std::vector<Connection>::iterator ConnectionIterator;
111  typedef typename std::vector<Connection>::const_iterator ConstConnectionIterator;
112 
113 public:
114 
116 
117  // Constructor / Destructor
118 
119  FrameLib_Object(ObjectType type, FrameLib_Context context, void *owner, T *parent)
120  : mType(type), mContext(context), mAllocator(context), mOwner(owner), mParent(parent), mNumIns(0), mNumOuts(0), mNumAudioChans(0), mSupportsOrderingConnections(false), mFeedback(false) {}
121  virtual ~FrameLib_Object() {}
122 
123  // Object Type
124 
125  ObjectType getType() const { return mType; }
126 
127  // Context
128 
129  FrameLib_Context getContext() const { return mContext; }
130 
131  // Owner
132 
133  void *getOwner() const { return mOwner; }
134 
135  // Queries
136 
137  unsigned long getNumIns() const { return mNumIns; }
138  unsigned long getNumOuts() const { return mNumOuts; }
139  unsigned long getNumAudioIns() const { return getType() != kOutput ? mNumAudioChans : 0; }
140  unsigned long getNumAudioOuts() const { return getType() == kOutput ? mNumAudioChans : 0; }
141  unsigned long getNumAudioChans() const { return mNumAudioChans; }
142 
143  // Set Fixed Inputs
144 
145  virtual void setFixedInput(unsigned long idx, double *input, unsigned long size) = 0;
146 
147  // Audio Processing
148 
149  // Override to handle audio at the block level (reset called with the audio engine resets)
150 
151  virtual void blockUpdate(double **ins, double **outs, unsigned long blockSize) = 0;
152  virtual void reset(double samplingRate, unsigned long maxBlockSize) = 0;
153 
154  // Return to host to request to be passed audio
155 
156  static bool handlesAudio() { return false; }
157 
158  // Info
159 
160  virtual std::string objectInfo(bool verbose = false) { return "No object info available"; }
161  virtual std::string inputInfo(unsigned long idx, bool verbose = false) { return "No input info available"; }
162  virtual std::string outputInfo(unsigned long idx, bool verbose = false) { return "No output info available"; }
163  virtual std::string audioInfo(unsigned long idx, bool verbose = false) { return "No audio channel info available"; }
164 
165  virtual FrameType inputType(unsigned long idx) const = 0;
166  virtual FrameType outputType(unsigned long idx) const = 0;
167 
168  // N.B. Parameter objects can be queried directly for info
169 
170  virtual const FrameLib_Parameters *getParameters() const { return NULL; }
171 
172  // Connection
173 
174  ConnectionResult addConnection(T *object, unsigned long outIdx, unsigned long inIdx)
175  {
176  ConnectionResult result = connectionCheck(object);
177  Queue queue;
178 
179  if (result == kConnectSuccess)
180  {
181  // Store data about connection and reset the dependency count
182 
183  T *prevObject = mConnections[inIdx].mObject;
184  mConnections[inIdx] = Connection(object, outIdx);
185 
186  // Update dependencies if the connection is now from a different object
187 
188  if (prevObject != object)
189  {
190  connectionRemoved(&queue, prevObject);
191  object->addOutputDependency(&queue, mParent);
192  }
193 
194  connectionUpdate(&queue);
195  }
196 
197  return result;
198  }
199 
200  void deleteConnection(unsigned long inIdx)
201  {
202  Queue queue;
203 
204  clearConnection(&queue, inIdx);
205  connectionUpdate(&queue);
206  }
207 
208  ConnectionResult addOrderingConnection(T *object, unsigned long outIdx)
209  {
210  if (!supportsOrderingConnections())
212 
213  ConnectionResult result = connectionCheck(object);
214  Queue queue;
215 
216  if (result == kConnectSuccess)
217  {
218  // If already connected there is nothing to do
219 
220  for (ConnectionIterator it = mOrderingConnections.begin(); it != mOrderingConnections.end(); it++)
221  if (it->mObject == object && it->mIndex == outIdx)
222  return kConnectSuccess;
223 
224  // Add the ordering connection
225 
226  mOrderingConnections.push_back(Connection(object, outIdx));
227 
228  // Update dependencies
229 
230  object->addOutputDependency(&queue, mParent);
231 
232  connectionUpdate(&queue);
233  }
234 
235  return result;
236  }
237 
238  void deleteOrderingConnection(T *object, unsigned long outIdx)
239  {
240  Queue queue;
241 
242  for (ConnectionIterator it = mOrderingConnections.begin(); it != mOrderingConnections.end(); it++)
243  {
244  if (it->mObject == object && it->mIndex == outIdx)
245  {
246  deleteOrderingConnection(&queue, it);
247  break;
248  }
249  }
250 
251  connectionUpdate(&queue);
252  }
253 
255  {
256  Queue queue;
257 
258  deleteOrderingConnections(&queue);
259  connectionUpdate(&queue);
260  }
261 
263  {
264  Queue queue;
265 
266  // Clear input connections
267 
268  for (unsigned long i = 0; i < mConnections.size(); i++)
269  clearConnection(&queue, i);
270 
271  // Delete ordering connections
272 
273  deleteOrderingConnections(&queue);
274 
275  // Delete output dependencies
276 
277  for (ObjectIterator it = mOutputDependencies.begin(); it != mOutputDependencies.end(); )
278  {
279  (*it)->disconnect(&queue, mParent);
280  it = mOutputDependencies.erase(it);
281  }
282 
283  connectionUpdate(&queue);
284  }
285 
286  bool isConnected(unsigned long inIdx) const
287  {
288  return mConnections[inIdx].mObject != NULL;
289  }
290 
291  virtual void autoOrderingConnections() = 0;
292  virtual void clearAutoOrderingConnections() = 0;
293 
294  // Connection Access
295 
296  T *getConnection(unsigned long idx) const { return mConnections[idx].mObject; }
297  unsigned long getConnectionIdx(unsigned long idx) const { return mConnections[idx].mIndex; }
298 
299  bool supportsOrderingConnections() const { return mSupportsOrderingConnections; }
300  unsigned long getNumOrderingConnections() const { return mOrderingConnections.size(); }
301  T *getOrderingConnection(unsigned long idx) const { return mOrderingConnections[idx].mObject; }
302  unsigned long getOrderingConnectionIdx(unsigned long idx) const { return mOrderingConnections[idx].mIndex; }
303 
304  bool isOrderingConnection(T *object) const
305  {
306  for (ConstConnectionIterator it = mOrderingConnections.begin(); it != mOrderingConnections.end(); it++)
307  if (it->mObject == object)
308  return true;
309 
310  return false;
311  }
312 
313  unsigned long getNumOutputDependencies() const { return mOutputDependencies.size(); }
314  T *getOutputDependency(unsigned long idx) const { return mOutputDependencies[idx]; }
315 
316 protected:
317 
318  // IO Setup
319 
320  void setIO(unsigned long nIns, unsigned long nOuts, unsigned long nAudioChans = 0)
321  {
322  mNumIns = (getType() == kScheduler || nIns) ? nIns : 1;
323  mNumOuts = nOuts;
324  mNumAudioChans = nAudioChans;
325 
326  mConnections.resize(mNumIns);
327  }
328 
329  // Ordering Setup
330 
331  void enableOrderingConnections() { mSupportsOrderingConnections = true; }
332 
333  // Memory Allocation
334 
335  template <class U> U *alloc(unsigned long N)
336  {
337  return reinterpret_cast<U *>(mAllocator->alloc(sizeof(U) * N));
338  }
339 
340  template <class U> void dealloc(U *& ptr)
341  {
342  mAllocator->dealloc(ptr);
343  ptr = NULL;
344  }
345 
346  void clearAllocator() { mAllocator->clear(); }
347 
348  FrameLib_LocalAllocator::Storage *registerStorage(const char *name) { return mAllocator->registerStorage(name); }
349 
351  {
352  mAllocator->releaseStorage(storage->getName());
353  storage = NULL;
354  }
355 
356  // Info Helpers
357 
358  static const char *formatInfo(const char *verboseStr, const char *briefStr, bool verbose)
359  {
360  return verbose ? verboseStr : briefStr;
361  }
362 
363  static std::string formatInfo(const char *verboseStr, const char *briefStr, unsigned long idx, bool verbose)
364  {
365  std::string info = formatInfo(verboseStr, briefStr, verbose);
366  std::string idxStr = numberedString("", idx + 1);
367 
368  for (size_t pos = info.find("#", 0); pos != std::string::npos; pos = info.find("#", pos + 1))
369  info.replace(pos, 1, idxStr);
370 
371  return info;
372  }
373 
374  static std::string formatInfo(const char *verboseStr, const char *briefStr, const char *replaceStr, bool verbose)
375  {
376  std::string info = formatInfo(verboseStr, briefStr, verbose);
377 
378  for (size_t pos = info.find("#", 0); pos != std::string::npos; pos = info.find("#", pos + 1))
379  info.replace(pos, 1, replaceStr);
380 
381  return info;
382  }
383 
384  // String With Number Helper
385 
386  static std::string numberedString(const char *str, unsigned long idx)
387  {
388  std::ostringstream outStr;
389 
390  outStr << str;
391  outStr << idx;
392 
393  return outStr.str();
394  }
395 
396 private:
397 
398  // Connection Methods (private)
399 
400  virtual void connectionUpdate(Queue *queue) = 0;
401 
402  // Connection Check
403 
404  ConnectionResult connectionCheck(T *object)
405  {
406  if (object == this)
407  return kConnectSelfConnection;
408 
409  if (object->mContext != mContext)
410  return kConnectWrongContext;
411 
412  if (detectFeedback(object))
414 
415  return kConnectSuccess;
416  }
417 
418  // Dependency Updating
419 
420  void addOutputDependency(Queue *queue, T *object)
421  {
422  for (ObjectIterator it = mOutputDependencies.begin(); it != mOutputDependencies.end(); it++)
423  if (*it == object)
424  return;
425 
426  mOutputDependencies.push_back(object);
427  connectionUpdate(queue);
428  }
429 
430  void deleteOutputDependency(Queue *queue, T *object)
431  {
432  for (ObjectIterator it = mOutputDependencies.begin(); it != mOutputDependencies.end(); it++)
433  {
434  if (*it == object)
435  {
436  mOutputDependencies.erase(it);
437  connectionUpdate(queue);
438  return;
439  }
440  }
441  }
442 
443  // Check whether a removed object is still connected somewhere, and if not update it's output dependencies
444 
445  void connectionRemoved(Queue *queue, T * object)
446  {
447  // Check that there is an object connected and that it is not connected to another input / ordering connection also
448 
449  if (!object)
450  return;
451 
452  for (ConnectionIterator it = mConnections.begin(); it != mConnections.end(); it++)
453  if (it->mObject == object)
454  return;
455 
456  for (ConnectionIterator it = mOrderingConnections.begin(); it != mOrderingConnections.end(); it++)
457  if (it->mObject == object)
458  return;
459 
460  // Update dependencies
461 
462  object->deleteOutputDependency(queue, mParent);
463  }
464 
465  // Delete connection and set to defaults
466 
467  void clearConnection(Queue *queue, unsigned long inIdx)
468  {
469  T *prevObject = mConnections[inIdx].mObject;
470  mConnections[inIdx] = Connection();
471  connectionRemoved(queue, prevObject);
472  }
473 
474  // Delete ordering connection
475 
476  ConnectionIterator deleteOrderingConnection(Queue *queue, ConnectionIterator it)
477  {
478  T *object = it->mObject;
479  it = mOrderingConnections.erase(it);
480  connectionRemoved(queue, object);
481 
482  return it;
483  }
484 
485  // Delete all ordering connections
486 
487  void deleteOrderingConnections(Queue *queue)
488  {
489  for (ConnectionIterator it = mOrderingConnections.begin(); it != mOrderingConnections.end(); )
490  it = deleteOrderingConnection(queue, it);
491  }
492 
493  // Remove all connections from a single object
494 
495  void disconnect(Queue *queue, T *object)
496  {
497  for (ConnectionIterator it = mConnections.begin(); it != mConnections.end(); it++)
498  if (it->mObject == object)
499  *it = Connection();
500 
501  for (ConnectionIterator it = mOrderingConnections.begin(); it != mOrderingConnections.end(); )
502  {
503  if (it->mObject == object)
504  it = mOrderingConnections.erase(it);
505  else
506  it++;
507  }
508 
509  connectionUpdate(queue);
510  }
511 
512  // Detect Potential Feedback in a Network
513 
514  bool detectFeedback(T *object)
515  {
516  object->mFeedback = false;
517  Queue queue(mParent, &T::feedbackProbe);
518  return object->mFeedback;
519  }
520 
521  void feedbackProbe(Queue *queue)
522  {
523  mFeedback = true;
524  for (typename std::vector <T *>::iterator it = mOutputDependencies.begin(); it != mOutputDependencies.end(); it++)
525  queue->add(*it, &T::feedbackProbe);
526  }
527 
528  // Data
529 
530  const ObjectType mType;
531  FrameLib_Context mContext;
532  FrameLib_Context::Allocator mAllocator;
533 
534  void *mOwner;
535  T *mParent;
536 
537  // IO Counts
538 
539  unsigned long mNumIns;
540  unsigned long mNumOuts;
541  unsigned long mNumAudioChans;
542 
543  // Connections
544 
545  std::vector<Connection> mOrderingConnections;
546  std::vector<Connection> mConnections;
547  std::vector<T *> mOutputDependencies;
548 
549  bool mSupportsOrderingConnections;
550  bool mFeedback;
551 };
552 
553 // FrameLib_Block
554 
555 // This abstract class provides a connectivity interface to FrameLib_DSP objects or blocks (groups of FrameLib_DSP objects).
556 // Standard objects inherit this in the FrameLib_DSP class.
557 // Objects that have asynchronous outputs can use this class to host multiple FrameLib_DSP objects and connect them correctly.
558 
559 class FrameLib_Block : public FrameLib_Object<FrameLib_Block>
560 {
561 
562 public:
563 
564  // Constructor / Destructor
565 
566  FrameLib_Block(ObjectType type, FrameLib_Context context, void *owner)
567  : FrameLib_Object<FrameLib_Block>(type, context, owner, this) {}
568  virtual ~FrameLib_Block() {}
569 
570  // Channel Awareness
571 
572  virtual void setChannel(unsigned long chan) {}
573 
574  // Connection Queries
575 
576  virtual unsigned long getNumInputObjects(unsigned long blockIdx) = 0;
577  virtual class FrameLib_DSP *getInputObject(unsigned long blockIdx, unsigned long idx) = 0;
578  virtual unsigned long getInputObjectIdx(unsigned long blockIdx, unsigned long idx) = 0;
579 
580  virtual class FrameLib_DSP *getOutputObject(unsigned long blockIdx) = 0;
581  virtual unsigned long getOutputObjectIdx(unsigned long blockIdx) = 0;
582 
583  virtual unsigned long getNumOrderingConnectionObjects() = 0;
584  virtual class FrameLib_DSP *getOrderingConnectionObject(unsigned long idx) = 0;
585 };
586 
587 #endif
ObjectType
Definition: FrameLib_Types.h:24
unsigned long getConnectionIdx(unsigned long idx) const
Definition: FrameLib_Object.h:297
bool isConnected(unsigned long inIdx) const
Definition: FrameLib_Object.h:286
virtual std::string objectInfo(bool verbose=false)
Definition: FrameLib_Object.h:160
void deleteConnection(unsigned long inIdx)
Definition: FrameLib_Object.h:200
virtual const FrameLib_Parameters * getParameters() const
Definition: FrameLib_Object.h:170
unsigned long getOrderingConnectionIdx(unsigned long idx) const
Definition: FrameLib_Object.h:302
Queue(T *object, Method method)
Definition: FrameLib_Object.h:27
unsigned long getNumOuts() const
Definition: FrameLib_Object.h:138
Definition: FrameLib_Parameters.h:21
unsigned long getNumOrderingConnectionObjects()
Definition: FrameLib_DSP.h:168
virtual ~FrameLib_Block()
Definition: FrameLib_Object.h:568
Definition: FrameLib_Context.h:10
T * getOutputDependency(unsigned long idx) const
Definition: FrameLib_Object.h:314
virtual unsigned long getOutputObjectIdx(unsigned long blockIdx)
Definition: FrameLib_DSP.h:166
void dealloc(U *&ptr)
Definition: FrameLib_Object.h:340
Definition: FrameLib_Types.h:26
Definition: FrameLib_DSP.h:17
FrameLib_LocalAllocator::Storage * registerStorage(const char *name)
Definition: FrameLib_Object.h:348
unsigned long getNumAudioChans() const
Definition: FrameLib_Object.h:141
virtual std::string outputInfo(unsigned long idx, bool verbose=false)
Definition: FrameLib_Object.h:162
virtual void setChannel(unsigned long chan)
Definition: FrameLib_Object.h:572
unsigned long mIndex
Definition: FrameLib_Object.h:103
FrameLib_DSP * getOutputObject(unsigned long blockIdx)
Definition: FrameLib_DSP.h:165
Definition: FrameLib_Object.h:13
T * getFirst() const
Definition: FrameLib_Object.h:65
static std::string formatInfo(const char *verboseStr, const char *briefStr, const char *replaceStr, bool verbose)
Definition: FrameLib_Object.h:374
ObjectType getType() const
Definition: FrameLib_Object.h:125
Queue()
Definition: FrameLib_Object.h:26
FrameLib_DSP * getInputObject(unsigned long blockIdx, unsigned long idx)
Definition: FrameLib_DSP.h:162
const char * getName() const
Definition: FrameLib_Memory.h:230
Definition: FrameLib_Object.h:91
void clearConnections()
Definition: FrameLib_Object.h:262
U * mObject
Definition: FrameLib_Object.h:102
unsigned long getNumOutputDependencies() const
Definition: FrameLib_Object.h:313
Definition: FrameLib_Types.h:26
FrameLib_Block(ObjectType type, FrameLib_Context context, void *owner)
Definition: FrameLib_Object.h:566
Definition: FrameLib_Object.h:97
virtual unsigned long getInputObjectIdx(unsigned long blockIdx, unsigned long idx)
Definition: FrameLib_DSP.h:163
FrameLib_Object(ObjectType type, FrameLib_Context context, void *owner, T *parent)
Definition: FrameLib_Object.h:119
ConnectionResult addOrderingConnection(T *object, unsigned long outIdx)
Definition: FrameLib_Object.h:208
Definition: FrameLib_Types.h:26
void clearAllocator()
Definition: FrameLib_Object.h:346
virtual std::string inputInfo(unsigned long idx, bool verbose=false)
Definition: FrameLib_Object.h:161
FrameLib_DSP * getOrderingConnectionObject(unsigned long idx)
Definition: FrameLib_DSP.h:169
FrameLib_Context getContext() const
Definition: FrameLib_Object.h:129
T * getOrderingConnection(unsigned long idx) const
Definition: FrameLib_Object.h:301
ConnectionResult addConnection(T *object, unsigned long outIdx, unsigned long inIdx)
Definition: FrameLib_Object.h:174
void clearOrderingConnections()
Definition: FrameLib_Object.h:254
bool supportsOrderingConnections() const
Definition: FrameLib_Object.h:299
bool isOrderingConnection(T *object) const
Definition: FrameLib_Object.h:304
Definition: FrameLib_Object.h:559
size_t blockSize(void *ptr)
Definition: FrameLib_Memory.cpp:23
void enableOrderingConnections()
Definition: FrameLib_Object.h:331
static bool handlesAudio()
Definition: FrameLib_Object.h:156
U * alloc(unsigned long N)
Definition: FrameLib_Object.h:335
UntypedConnection()
Definition: FrameLib_Object.h:99
FrameLib_Queueable()
Definition: FrameLib_Object.h:18
unsigned long getNumOrderingConnections() const
Definition: FrameLib_Object.h:300
virtual std::string audioInfo(unsigned long idx, bool verbose=false)
Definition: FrameLib_Object.h:163
void setIO(unsigned long nIns, unsigned long nOuts, unsigned long nAudioChans=0)
Definition: FrameLib_Object.h:320
void deleteOrderingConnection(T *object, unsigned long outIdx)
Definition: FrameLib_Object.h:238
virtual ~FrameLib_Object()
Definition: FrameLib_Object.h:121
static std::string formatInfo(const char *verboseStr, const char *briefStr, unsigned long idx, bool verbose)
Definition: FrameLib_Object.h:363
Definition: FrameLib_Object.h:20
void releaseStorage(FrameLib_LocalAllocator::Storage *&storage)
Definition: FrameLib_Object.h:350
T * getConnection(unsigned long idx) const
Definition: FrameLib_Object.h:296
unsigned long getNumAudioOuts() const
Definition: FrameLib_Object.h:140
unsigned long getNumAudioIns() const
Definition: FrameLib_Object.h:139
Definition: FrameLib_Types.h:24
ConnectionResult
Definition: FrameLib_Types.h:26
FrameType
Definition: FrameLib_Types.h:25
static const char * formatInfo(const char *verboseStr, const char *briefStr, bool verbose)
Definition: FrameLib_Object.h:358
Definition: FrameLib_Memory.h:220
ManagedPointer< FrameLib_LocalAllocator, &Global::getAllocator, &Global::releaseAllocator > Allocator
Definition: FrameLib_Context.h:84
Definition: FrameLib_Types.h:24
void add(T *object, Method method)
Definition: FrameLib_Object.h:29
FrameLib_Queueable< T >::Queue Queue
Definition: FrameLib_Object.h:115
unsigned long getNumIns() const
Definition: FrameLib_Object.h:137
static std::string numberedString(const char *str, unsigned long idx)
Definition: FrameLib_Object.h:386
Definition: FrameLib_Types.h:26
Definition: FrameLib_Types.h:26
void * getOwner() const
Definition: FrameLib_Object.h:133
UntypedConnection(U *object, unsigned long index)
Definition: FrameLib_Object.h:100